import json
import time
import datetime
from typing import Any
from typing import List
from typing import Union
from apis import api_routes
from sqlalchemy import desc
from sqlalchemy import and_
from sqlalchemy import text
from sqlalchemy import func
from flask import abort, g, request, jsonify
from models.course.course import Course
from models.order.tasks import Tasks
from models.product.craft import Craft
from models.course.serial import Serial
from models.course.detailed import Detailed
from models.facility.facility import Facility
from models.product.routes import Routes
from models.product.aircraft import Aircraft
from security.decoration import certification
from public.contexts import context_logs


@api_routes.route("/tasks", methods=["POST"])
@certification(auth=True, role=None)
def func_tasks_post_api():
    """
    添加工单操作接口，完成API开发
    http://127.0.0.1:8080/api/tasks
    Content-Type=application/json
    methods=["POST"]
    {
    "orders":    string  ****  订单编号
    "name"       string  ****  任务名称
    "amount"     int     ****  总共计划生产数量
    "time"       string  ****  计划生产时间，格式 %Y-%m-%d
    "aircraft_id"    string   ****  产品机种名称  /api/aircraft/all GET 拿数据
    }
    :return:
        {'status': 4000, "msg": "计划数量必须大于0"}
        {'status': 4001, "msg": "没有找到机种"}
        {'status': 200, "msg": "添加工单成功"}
     ---
    tags:
      - 工单管理模块
    """
    data: dict = request.get_json()
    orders: str = data.get("orders")
    name: str = data.get("name")
    amount: int = data.get("amount")
    times: str = data.get("time")
    aircraft_id: int = data.get("aircraft_id")

    if not all([orders, name, amount, times, aircraft_id]):
        abort(400)
    amount: int = int(amount)
    if amount <= 0:
        return jsonify({'status': 4000, "msg": "计划数量必须大于0"})
    date_type = datetime.datetime.strptime(times, "%Y-%m-%d")

    aircraft: Aircraft = g.session.query(Aircraft).filter(Aircraft.id == aircraft_id).first()
    if aircraft is None:
        return jsonify({'status': 4001, "msg": "没有找到机种"})

    g.session.add(Tasks(
        orders=orders, name=name, amount=amount,
        totals=0, actual=0, aircraft_id=aircraft_id,
        time=date_type, delivery=None, status=False
    ))
    context_logs(name="创建新的工单", obsolescence=None, data=json.dumps(data))

    g.session.commit()
    return jsonify({'status': 200, "msg": "添加工单成功"})


@api_routes.route("/tasks", methods=["GET"])
@certification(auth=True, role=None)
def func_tasks_get_api():
    """
    查询工单接口, 可以任意组合， 记得有七种组个方式，完成API开发
    参数要么不带， 带的话必须要有参数
    http://127.0.0.1:8080/api/tasks
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "index"     int      ****  第几页，默认为1
    "size"      int      ****  每页数据多少, 默认每页10条数据
    "orders"    string   工单对应订单编号
    "status"    string   工单是否完成 [unfinished, finished, running]
    "start"     string   计划生产时间段开始   格式 %Y-%m-%d
    "finish"    string   计划生产时间段完成   格式 %Y-%m-%d
    }
    :return:
        {'status': 200, 'data': "data", }
    ---
    tags:
      - 工单管理模块
    """
    size = request.args.get("size", default=10, type=int)
    index = request.args.get("index", default=1, type=int)
    # 整合参数
    orders: Union[str, None] = request.args.get("orders", default=None, type=str)
    status: Union[str, None] = request.args.get("status", default=None, type=str)

    start = request.args.get("start", default=None, type=str)
    finish = request.args.get("finish", default=None, type=str)

    if orders is not None and len(orders) == 0:
        orders = None
    if status is not None and len(status) == 0:
        status = None

    if start is not None and len(start) == 0:
        start = None
    if finish is not None and len(finish) == 0:
        finish = None

    if status is not None and status not in ["unfinished", "finished", "running"]:
        abort(400)

    if start is not None and finish is None:
        return jsonify({'status': 4000, "msg": "start, finish必须成对存在"})
    if start is None and finish is not None:
        return jsonify({'status': 4000, "msg": "start, finish必须成对存在"})

    parameter: list = []
    if orders is not None:
        parameter.append(Tasks.orders.like("%" + orders + "%"))
    if status is not None and status == "finished":
        parameter.append(Tasks.actual >= Tasks.amount)
    elif status is not None and status == "unfinished":
        parameter.append(Tasks.actual < Tasks.amount)
    elif status is not None and status == "running":
        parameter.append(Tasks.status == 't')
    if start is not None:
        start1 = datetime.datetime.strptime(start, "%Y-%m-%d")
        parameter.append(Tasks.time >= start1)
    if finish is not None:
        finish1 = datetime.datetime.strptime(finish, "%Y-%m-%d")
        parameter.append(Tasks.time <= finish1)

    count = g.session.query(Tasks.id).filter(* parameter).count()
    data: List[Tasks] = g.session.query(Tasks).filter(* parameter).order_by(desc(Tasks.id)).offset((index - 1) * size).limit(size).all()

    page: int = int((count / size) + 1) if (count / size) > int(count / size) else int(count / size)

    sp: list = []
    for index, itr in enumerate(data):
        aircraft: Aircraft = g.session.query(Aircraft).filter(Aircraft.id == itr.aircraft_id).first()

        status: str = "未完成"
        if itr.amount > itr.actual:
            status: str = "未完成"
        if itr.amount <= itr.actual:
            status: str = "已完成"
        if itr.status is True:
            status: str = "进行中"

        sp.append({
            "task_id": itr.id,
            "orders": itr.orders,
            "name": itr.name,
            "aircraft_id": aircraft.id,
            "aircraft": aircraft.aircraft,
            "amount": itr.amount,
            "totals": itr.totals,
            "actual": itr.actual,
            "time": itr.time.strftime("%Y-%m-%d"),
            "delivery": itr.delivery.strftime("%Y-%m-%d") if itr.delivery else None,
            "status": status,
            "status2": itr.status,
        })
    doc: dict = {
        "task_id": "数据库ID",
        "orders": "订单编号",
        "name": "工单名称",
        "serials": "机种编码",
        "aircraft": "机种名称",
        "amount": "计划生产数量",
        "totals": "总生产量",
        "actual": "合格数量",
        "time": "计划生产时间",
        "delivery": "生产完工时间",
        "status": "工单状态  未完成 已完成 进行中",
    }
    return jsonify({'status': 200, 'data': sp, "index": index, "size": size, "total": count, "pages": page, "doc": doc})


@api_routes.route("/tasks", methods=["PUT"])
@certification(auth=True, role=None)
def func_tasks_put_api():
    """
    修改工单接口参数，完成API开发
    http://127.0.0.1:8080/api/tasks
    Content-Type=application/json
    methods=["PUT"]
    {
    "orders":    string    订单编号
    "name"       string    任务名称
    "amount"     int       总共计划生产数量
    "time"       string    计划生产时间
    }
    :return:
        {'status': 4000, "msg": "没有找到工单"}
        {'status': 200, "msg": "更新工单成功"}
     ---
    tags:
      - 工单管理模块
    """
    data: dict = request.get_json()
    task_id: int = data.get("task_id")
    orders: str = data.get("orders")
    name: str = data.get("name")
    amount: int = data.get("amount")
    times: str = data.get("time")
    sample: int = data.get("sample")

    if task_id is None:
        abort(400)
    task: Tasks = g.session.query(Tasks).filter(Tasks.id == task_id).first()
    if task is None:
        return jsonify({'status': 4000, "msg": "没有找到工单"})

    context_logs(name="修改工单信息", obsolescence=task.__repr__(), data=json.dumps(data))

    if orders is not None and orders != task.orders:
        task.orders = orders

    if name is not None and name != task.name:
        task.name = name

    if amount is not None and amount != task.amount:
        task.amount = amount

    if times is not None:
        task.time = datetime.datetime.strptime(times, "%Y-%m-%d")

    if sample is not None:
        task.sample = True if int(sample) else False

    g.session.commit()
    return jsonify({'status': 200, "msg": "更新工单成功"})


@api_routes.route("/tasks", methods=["DELETE"])
@certification(auth=True, role=None)
def func_tasks_delete_api():
    """
    删除工单接口，完成API开发
    http://127.0.0.1:8080/api/tasks
    Content-Type=application/json
    methods=["DELETE"]
    {
    "task_id"     int    ****  工单ID
    }
    :return:
        {'status': 4000, "msg": "没有找到工单"}
        {'status': 200, "msg": "删除工单成功"}
     ---
    tags:
      - 工单管理模块
    """
    data: dict = request.get_json()
    task_id: int = data.get("task_id")

    if task_id is None:
        abort(400)
    task: Tasks = g.session.query(Tasks).filter(Tasks.id == task_id).first()
    if task is None:
        return jsonify({'status': 4000, "msg": "没有找到工单"})

    g.session.query(Serial).filter(Serial.tasks_id == task_id).delete()
    g.session.query(Detailed).filter(Detailed.tasks_id == task_id).delete()
    g.session.query(Course).filter(Course.tasks_id == task_id).delete()

    context_logs(name="删除工单信息", obsolescence=task.__repr__(), data=json.dumps(data))

    g.session.query(Tasks).filter(Tasks.id == task_id).delete()
    g.session.commit()
    return jsonify({'status': 200, "msg": "删除工单成功"})


@api_routes.route("/tasks/status", methods=["PUT"])
@certification(auth=True, role=None)
def func_tasks_status_put_api():
    """
    修改工单状态, tasks.status == True 表示做哪个工单任务，完成API开发
    http://127.0.0.1:8080/api/tasks/status
    Content-Type=application/json
    methods=["PUT"]
    {
    "task_id"     int        ****   工单ID
    "status"      int[0, 1]  ****   设置状态
    }
    :return:
        {'status': 4000, "msg": "没有找到工单"}
        {'status': 4001, 'msg': "已生产数量大于或等于计划数量, 任务完成, 生产别的任务"}
        {'status': 200, "msg": "设置订单状态成功"}
     ---
    tags:
      - 工单管理模块
    """
    data: dict = request.get_json()
    task_id: int = data.get("task_id")
    status: int = data.get("status")

    if task_id is None or status is None or (int(status) not in [0, 1]):
        abort(400)
    value: bool = True if int(status) else False

    task: Tasks = g.session.query(Tasks).filter(Tasks.id == task_id).first()
    if task is None:
        return jsonify({'status': 4000, "msg": "没有找到工单"})

    sql = "UPDATE tasks SET status='f' WHERE tasks.id != :task_id AND (tasks.status is null or tasks.status = 't')"
    g.session.execute(text(sql), {"task_id": task_id})
    g.session.commit()

    if task.actual >= task.amount:
        return jsonify({'status': 4001, 'msg': "已生产数量大于或等于计划数量, 任务完成, 生产别的任务"})

    if value is True:
        need_number: int = task.amount - task.actual
        if need_number < 0:
            need_number = 0
        db_aircraft: Aircraft = g.session.query(Aircraft).filter(Aircraft.id == task.aircraft_id).first()
        db_route: Routes = g.session.query(Routes).filter(Routes.id == db_aircraft.route_id).first()

        # ft_ids: list = []
        # route_new = json.loads(db_route.route)
        # routes_new = route_new.get("data")
        # for itr1 in routes_new:
        #     second_rts = itr1.get("ft_ids")
        #     for itr2 in second_rts:
        #         ft_ids.append(itr2)
        # ft_ids: list = list(set(ft_ids))
        #
        # # ############################################################
        # if 1 not in ft_ids:
        #     ft_ids.append(1)
        # if 6 in ft_ids and 8 in ft_ids:
        #     ft_ids.append(7)
        # ft_ids.sort()
        # ############################################################

        ft_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

        if value is True:
            for itr in ft_ids:
                if itr not in [2, 3]:
                    db_ft: Facility = g.session.query(Facility).filter(Facility.id == itr).first()
                    uuid_key = str(db_ft.uuid4)
                    redis_status_key: str = "status-{}".format(uuid_key)
                    redis_status_value = g.cache.get(redis_status_key)
                    if redis_status_value is None or str(redis_status_value) == "8":
                        return jsonify({'status': 4005, "msg": "设备{}在自动运行状态，无法下发配方".format(db_ft.name)})

        ft_keys: list = []
        for _, ft_id in enumerate(ft_ids):
            db_ft: Facility = g.session.query(Facility).filter(Facility.id == ft_id).first()
            uuid_key = str(db_ft.uuid4)
            uuid_key = "queues-{}".format(uuid_key)
            ft_keys.append(uuid_key)

            db_craft: List[Craft] = g.session.query(Craft).filter(and_(
                            Craft.aircraft_id == task.aircraft_id,
                            Craft.facility_id == ft_id
                        )).all()
            for db_ct in db_craft:
                value_bool = False
                write_allow = ["Bool", "Short", "Int", "Float", "String"]

                if db_ct.write is not None and len(str(db_ct.write).replace(" ", "")) != 0:
                    value_bool = True

                if value_bool and db_ct.types in write_allow:
                    data_write: dict = {"address": db_ct.address, "type": db_ct.types, "value": db_ct.write}

                    g.cache.rpush(uuid_key, json.dumps(data_write))
                    g.cache.expire(uuid_key, 8)

                    # print(ft_id, uuid_key, json.dumps(data_write))

            # 整线换型时写入设备型号序号给各设备, 配方号
            parm_data: list = db_aircraft.aircraft.split("-")
            value_index = int(parm_data[len(parm_data) - 1])

            # 目标产量, 绕线机
            if ft_id in [3, 4, 5, 6]:
                g.cache.rpush(uuid_key, json.dumps({"address": "DM4102", "type": "Short", "value": value_index}))
                g.cache.expire(uuid_key, 8)

                g.cache.rpush(uuid_key, json.dumps({"address": "DM4106", "type": "Int", "value": need_number}))
                g.cache.expire(uuid_key, 8)

                g.cache.rpush(uuid_key, json.dumps({"address": "DM4104", "type": "Short", "value": 1}))
                g.cache.expire(uuid_key, 8)

            elif ft_id in [1, 2, 9, 10, 11]:
                g.cache.rpush(uuid_key, json.dumps({"address": "DM8062", "type": "Short", "value": value_index}))
                g.cache.expire(uuid_key, 8)

                g.cache.rpush(uuid_key, json.dumps({"address": "DM8066", "type": "Int", "value": need_number}))
                g.cache.expire(uuid_key, 8)

                # MES通知设备写入工单数量赋值1，设备收到后写0，MES收到0证明设备换型更新目标产量成功
                g.cache.rpush(uuid_key, json.dumps({"address": "DM8064", "type": "Short", "value": 1}))
                g.cache.expire(uuid_key, 8)

        start = time.time()
        interval = 4.2
        write_all: bool = False
        write_all_mark: list = []
        while True:
            temp = round(time.time() - start, 3)
            if (interval - temp) <= 0:
                break
            write_all_mark.clear()
            for index, itr in enumerate(ft_ids):
                length: int = g.cache.llen(ft_keys[index])
                mark: bool = True if length == 0 else False
                write_all_mark.append(mark)

            if all(write_all_mark) is True:
                write_all = True
                break
        if write_all is False:
            return jsonify({'status': 4004, "msg": "MES与PLC设备通讯存在异常"})

    task.status = value
    g.session.commit()
    return jsonify({'status': 200, "msg": "设置订单状态成功"})


@api_routes.route("/tasks/context/details", methods=["GET"])
@certification(auth=True, role=None)
def func_tasks_context_details_get_api():
    """
    根据工单ID查询这个工单已做的产品SN码，前端可以选择是否分页, 完成API开发
    http://127.0.0.1:8080/api/tasks/context/details
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "task_id"    int      ****  对应的工单ID
    "is_page"    int            是否分页操作,1分页，0不分页
    "index"      int      ****  第几页，默认为1
    "size"       int      ****  每页数据多少, 默认每页10条数据
    }
    :return:
        {'status': 200, 'data': "data", }
    ---
    tags:
      - 工单管理模块
    """
    task_id = request.args.get("task_id", default=None, type=int)
    is_page = request.args.get("is_page", default=1, type=int)
    size = request.args.get("size", default=10, type=int)
    index = request.args.get("index", default=1, type=int)

    if task_id is None:
        abort(400)
    count = g.session.query(Course.id).filter(Course.tasks_id == task_id).count()
    page: int = int((count / size) + 1) if (count / size) > int(count / size) else int(count / size)

    data: List[Course] = g.session.query(Course).filter(
        Course.tasks_id == task_id
    ).order_by(Course.id).offset((index - 1) * size).limit(size).all()
    if is_page == 0:
        data: List[Course] = g.session.query(Course).filter(Course.tasks_id == task_id).order_by(Course.id).all()

    rsp: list = []
    parm: dict = {0: "未完成", 1: "合格", 2: "不合格", 3: "报废"}
    for index, itr in enumerate(data):
        rsp.append({
            "sequence": itr.sequence,
            "mark": parm.get(itr.mark),
            "message": itr.message,
            "start": itr.start.strftime("%Y-%m-%d %H:%M:%S"),
            "finish": itr.finish.strftime("%Y-%m-%d %H:%M:%S") if itr.finish else None
        })

    doc: dict = {
        "sequence": "产品SN",
        "mark": "产品状态（未完成，合格，不合格，报废）",
        "message": "报废原因",
        "start": "开始时间",
        "finish": "结束时间"
    }
    return jsonify({'status': 200, 'data': rsp, "index": index, "size": size, "total": count, "pages": page, "doc": doc})
